package view;

import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.geom.RoundRectangle2D;
import java.awt.Color;

import model.*;

/**
 * PacEditorCanvas is used to draw the screen area for the level editor
 * of tb-pacman. It supports highlighting selected tiles, drawing
 * Pacman and ghosts based on spawn points instead of actual gameplay objects,
 * and reloading the maze whenever it is changed.
 * 
 * @author Alexander Craig
 */
@SuppressWarnings("serial")
public class PacEditorCanvas extends PacCanvas implements EditorListener {

	/** the LevelEditor instance to listen on */
	private LevelEditor editor;
	
	/**
	 * Generates a new instance of PacEditorCanvas
	 * @param editor	the editor to watch
	 */
	public PacEditorCanvas(LevelEditor editor) {
		this.editor = editor;
		editor.addEditorListener(this);
	}
	
	/**
	 * Highlights the primary and secondary selected tiles in the watched editor object
	 * @param buffedG2D	the buffer to draw to
	 */
	public void drawSelectedTiles(Graphics2D buffedG2D) {
		if (buffedG2D == null)
			return;
		
		Tile selected = editor.getSelectedTile();
		if (selected != null) {
			buffedG2D.setColor(new Color(46, 108, 200));
			buffedG2D.fill(new RoundRectangle2D.Double(selected.getXCoord() * TILE_SPREAD,
					selected.getYCoord() * TILE_SPREAD,
					TILE_SPREAD, TILE_SPREAD, TILE_SPREAD/2,TILE_SPREAD/2));
		}
		selected = editor.getSecondaryTile();
		if (selected != null) {
			buffedG2D.setColor(new Color(126, 19, 19));
			buffedG2D.fill(new RoundRectangle2D.Double(selected.getXCoord() * TILE_SPREAD,
					selected.getYCoord() * TILE_SPREAD,
					TILE_SPREAD, TILE_SPREAD, TILE_SPREAD/2,TILE_SPREAD/2));
		}
	}
	
	/**
	 * Draw the pass dots setting and the level title onto the screen
	 * @param g2D	the graphics buffer to draw to
	 */
	public void drawEditorUI(Graphics2D g2D) {
		if (getLoadedMaze() == null || g2D == null)
			return;
		// Set font to use for drawing
		Font font = new Font(DEFAULT_FONTS, Font.PLAIN, DEFAULT_FONT_SIZE);
		g2D.setFont(font);
	    g2D.setColor(Color.YELLOW);
		
		// Draw dots, lives and score indicators
	    g2D.drawString(editor.getMaze().getPassDots() + " dots to pass", 0, (editor.getMaze().getMaxY()*(int)TILE_SPREAD) + 40);
	    FontMetrics metrics = g2D.getFontMetrics(font);
	    int titleWidth = metrics.stringWidth(editor.getLevel().getTitle());
	    g2D.drawString(editor.getLevel().getTitle(), 
	    		(int)((editor.getMaze().getMaxX()*TILE_SPREAD) - titleWidth) / 2, -15);
	}
	
	@Override
	/**
	 * Draws all editor elements onto the back buffer
	 */
	public void drawBackBuffer(Graphics2D buffedG2D) {
		drawMazeLower(buffedG2D);	// Draw the lower maze layer
		drawSelectedTiles(buffedG2D); // Highlights the currently selected tile
		drawMazeDots(buffedG2D); // White dots in the centre of unvisited tiles
		
		// Create a Player object to be drawn based on the player spawn point, if one exists
		try {
			drawPacman(new Player(editor.getLevel().getPlayerStart(),3), buffedG2D);
		} catch (NullPointerException e) {
			// Expected exception when no spawn point is placed
		}
		
		// Create Ghost objects to be drawn based on the ghost spawn point
		if(editor != null && editor.getLevel() != null) {
			GameLevel level = editor.getLevel();
			for(int i = 0; i < level.getNumSpawnPoints(); i++) {
				SpawnPoint s = level.getSpawnPoint(i);
				switch(s.getSpawnType()){
				case GHOST_HORIZONTAL:
					drawGhost(new Ghost(s.getSpawnTile(), null, Ghost.HORIZONTAL), buffedG2D);
					break;
				case GHOST_VERTICAL:
					drawGhost(new Ghost(s.getSpawnTile(), null, Ghost.VERTICAL), buffedG2D);
					break;
				case GHOST_RANDOM:
					drawGhost(new Ghost(s.getSpawnTile(), null, Ghost.RANDOM), buffedG2D);
					break;
				}
			}
		}
		
		drawMazeUpper(buffedG2D);	// Draw the upper maze layer
		drawEditorUI(buffedG2D);	// Draw the level name and dots to pass
	}

	@Override
	/**
	 * Loads the new maze into the Canvas' memory, then repaints the canvas
	 * when a maze is modified
	 */
	public void mazeChange(EditorEvent event) {
		loadMaze(event.getSource().getMaze());
		repaint();
	}

	@Override
	/**
	 * Loads the new maze into the Canvas' memory, then repaints the canvas
	 * when a new level is loaded.
	 */
	public void newLevel(EditorEvent event) {
		loadMaze(event.getSource().getMaze());
		repaint();
	}

	@Override
	/**
	 * Repaints the canvas when the selection changes.
	 */
	public void selectionChange(EditorEvent event) {
		repaint();
	}

	@Override
	public void toolChange(EditorEvent event) {}

}
